fix(auto-merge): delete head branch after app-merged PRs#30
Conversation
delete_branch_on_merge fires for user merges but not for merges landed by the github-actions app via native auto-merge — observed fleet-wide (qyl claude/ branches from #452-#456 and #477-#479 all survived their merges; the user-merged #476 was deleted). Add a delete-merged-branch job on the closed event, scoped to same-repo claude/ and copilot/ heads, with the ref passed via env so pull_request_target cannot be shell-injected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Caution Review failedThe pull request is closed. Note
|
| Layer / File(s) | Summary |
|---|---|
Trigger and gating updates .github/workflows/auto-merge.yml, templates/auto-merge.yml |
Adds closed to the pull_request_target trigger types, adds explanatory comments, and updates enable-auto-merge's condition to exclude closed events. |
Delete-merged-branch job .github/workflows/auto-merge.yml, templates/auto-merge.yml |
Introduces a new job that runs on closed+merged PRs from claude/ or copilot/ branches, deleting the head branch via gh api -X DELETE using a HEAD_REF env var and tolerating already-deleted branches. |
Estimated code review effort: 2 (Simple) | ~10 minutes
Sequence Diagram(s)
sequenceDiagram
participant GitHub
participant AutoMergeWorkflow
participant DeleteMergedBranchJob
participant GhCli
GitHub->>AutoMergeWorkflow: pull_request_target (closed, merged=true)
AutoMergeWorkflow->>DeleteMergedBranchJob: verify head branch prefix (claude/ or copilot/)
DeleteMergedBranchJob->>GhCli: gh api -X DELETE (HEAD_REF)
GhCli-->>DeleteMergedBranchJob: branch deleted or already absent
Related Issues: None specified.
Related PRs: None specified.
Suggested labels: ci, automation, workflow
Suggested reviewers: ANcpLua
✨ Finishing Touches
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
claude/automerge-branch-cleanup
✨ Simplify code
- Create PR with simplified code
- Commit simplified code in branch
claude/automerge-branch-cleanup
- 🛠️ repair automation
- 🛠️ cleanup stale review automation
Comment @coderabbitai help to get the list of available commands.
There was a problem hiding this comment.
Pull request overview
Adds a workflow-level cleanup step to ensure automation PR head branches (e.g., claude/, copilot/) are deleted after GitHub Actions app–landed native auto-merges, closing a gap where the repo-level delete_branch_on_merge setting doesn’t reliably delete app-merged branches across the fleet.
Changes:
- Extend
pull_request_targettriggers to includeclosed. - Gate the existing
enable-auto-mergejob to skipclosedevents. - Add a
delete-merged-branchjob that runs on merged PR close events and deletes same-repoclaude//copilot/head branches.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| templates/auto-merge.yml | Adds closed trigger + new delete-merged-branch cleanup job to the fleet template. |
| .github/workflows/auto-merge.yml | Applies the same cleanup behavior in this repo’s workflow copy. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| run: | | ||
| gh api -X DELETE "repos/${{ github.repository }}/git/refs/heads/$HEAD_REF" \ | ||
| || echo "head branch already deleted" |
| run: | | ||
| gh api -X DELETE "repos/${{ github.repository }}/git/refs/heads/$HEAD_REF" \ | ||
| || echo "head branch already deleted" |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 86811cafa0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| on: | ||
| pull_request_target: | ||
| types: [opened, synchronize, reopened, ready_for_review] | ||
| types: [opened, synchronize, reopened, ready_for_review, closed] |
There was a problem hiding this comment.
Don’t rely on closed events from GITHUB_TOKEN auto-merges
For the app-merged PRs this is meant to clean up, the merge is caused by this workflow’s secrets.GITHUB_TOKEN auto-merge call, and GitHub documents that GITHUB_TOKEN-triggered events do not create workflow runs except workflow_dispatch, repository_dispatch, and pull_request opened/synchronize/reopened; closed is explicitly excluded (docs). Adding closed here therefore will not start the new deletion job for the github-actions native auto-merges whose branches are surviving, so the fleet cleanup remains ineffective unless the merge/delete path uses a PAT/App token or another dispatch/wait mechanism.
Useful? React with 👍 / 👎.
| HEAD_REF: ${{ github.event.pull_request.head.ref }} | ||
| run: | | ||
| gh api -X DELETE "repos/${{ github.repository }}/git/refs/heads/$HEAD_REF" \ | ||
| || echo "head branch already deleted" |
There was a problem hiding this comment.
Fail on branch deletion errors other than 404
When this job does run, this catch-all makes the workflow succeed for every gh api failure, not only the already-deleted branch case; GitHub CLI documents that failed commands return a nonzero exit code (docs), and the delete-ref API has distinct failure statuses such as 409/422 (docs). If a token permission, ruleset, API validation, or transient service failure prevents deletion, the step still ends green after printing “head branch already deleted,” so branch cleanup can silently do nothing.
Useful? React with 👍 / 👎.
Complete-and-verified
Gap: repo-level
delete_branch_on_mergefires for user-initiated merges but not for merges landed by the github-actions app via native auto-merge. Observed in qyl today:claude/branches of #452–#456 and #477–#479 (all app-merged) survived; the user-merged #476 was auto-deleted. That's why merged automation branches accumulate across the fleet.Fix:
templates/auto-merge.yml(+ this repo's own copy) gains adelete-merged-branchjob onpull_request_target: closed:merged == true, same-repo head, and theclaude//copilot/prefix policyenable-auto-mergejob now skips theclosedactionHEAD_REFpassed viaenvand never interpolated into the script — no shell injection underpull_request_target's write token|| echo) for branches already gone via the repo settingPropagation: next weekly
enforce-repo-settingssweep replaces drifted per-repo copies; I'll dispatch it manually after merge so the fleet converges today.🤖 Generated with Claude Code